import requests
import cv2
import time
import logging
from requests import ReadTimeout, ConnectTimeout, ConnectionError
from threading import Thread, Lock

# 配置日志记录
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')

# 使用场景多数是要根据其它信息控制是否开启摄像头, 又因为要在大循环里运行, 因此继承线程类方便管理
class VideoThread(Thread):
    def __init__(self, device="/dev/video0"):
        super().__init__()
        self.cap = None
        self.should_stop = False
        self.lock = Lock()
        self.device = device  # 新增设备参数

    def run(self) -> None:
        max_retries = 3
        retry_count = 0
        while retry_count < max_retries:
            # 修改为使用参数化的设备路径
            self.cap = cv2.VideoCapture(self.device, cv2.CAP_V4L2)  # 明确指定使用V4L2后端
            if self.cap.isOpened():
                # 设置合理的摄像头参数
                self.cap.set(cv2.CAP_PROP_FRAME_WIDTH, 640)
                self.cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 480)
                target_fps = 30
                while target_fps >= 10:  # 最低不低于10fps
                    if self.cap.set(cv2.CAP_PROP_FPS, target_fps):
                        actual_fps = self.cap.get(cv2.CAP_PROP_FPS)
                        logging.info(f"成功设置帧率: 目标 {target_fps}fps, 实际 {actual_fps}fps")
                        break
                    target_fps -= 5  # 每次降低5fps
                else:
                    logging.warning("无法设置合理帧率，使用默认值")
                break
            else:
                logging.warning(f"摄像头 {self.device} 初始化失败，尝试第 {retry_count + 1} 次重试")
                retry_count += 1
                time.sleep(2)
        else:
            logging.error(f"摄像头 {self.device} 初始化失败，达到最大重试次数")
            return

        while True:
            with self.lock:
                if self.should_stop:
                    break
            
            start_time = time.time()
            
            # 增加帧读取重试机制
            retry_read_count = 0
            max_read_retries = 3
            while retry_read_count < max_read_retries:
                ret, frame = self.cap.read()
                if ret:
                    # 在图像上添加文字信息
                    try:
                        # 获取当前分辨率
                        width = int(self.cap.get(cv2.CAP_PROP_FRAME_WIDTH))
                        height = int(self.cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
                        fps = self.cap.get(cv2.CAP_PROP_FPS)
                        
                        # 添加文字到帧上
                        text = f"{width}x{height} @ {fps:.1f}fps"
                        cv2.putText(frame, text, (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 
                                   0.8, (0, 255, 0), 2, cv2.LINE_AA)
                        
                        # 继续原有的图像编码和发送逻辑
                        _, img_encoded = cv2.imencode(".jpg", frame)
                        max_request_retries = 3
                        request_retry_count = 0
                        while request_retry_count < max_request_retries:
                            try:
                                # 发送到服务器, 设置超时时间防止阻塞, 如果服务器性能一般般尽量不要发太快
                                response = requests.post("http://192.168.10.129:8000/upload", data=img_encoded.tobytes(),
                                                         timeout=1)  # 发送图像数据
                                if response.status_code != 200:
                                    logging.warning(f"接口名字可能写错了，状态码: {response.status_code}")
                                break
                            except ReadTimeout:
                                # 因为设置了超时很容易网络原因超时, 丢几帧画面是可接受的
                                logging.warning("请求超时，丢弃当前帧")
                                break
                            except (ConnectTimeout, ConnectionError):
                                logging.warning("服务端可能还没开起来，尝试重新连接...")
                                request_retry_count += 1
                                time.sleep(2)
                            except Exception as e:
                                logging.error(f"发生未知异常: {e}")
                                request_retry_count += 1
                                time.sleep(2)
                    except Exception as e:
                        logging.error(f"图像处理异常: {e}")
                        continue  # 跳过当前帧继续下一帧
            
            # 计算处理耗时并控制帧率
            process_time = time.time() - start_time
            target_interval = 1.0 / self.cap.get(cv2.CAP_PROP_FPS) if self.cap.get(cv2.CAP_PROP_FPS) > 0 else 0.033  # 默认30fps
            if process_time < target_interval:
                time.sleep(target_interval - process_time)

        # 将资源释放移到循环外部
        self.release_resources()

    def release_resources(self):
        try:
            if self.cap:
                self.cap.release()
            cv2.destroyAllWindows()
            logging.info("资源释放成功")
        except Exception as e:
            logging.error(f"释放资源时出错: {e}")

    def stop(self):
        with self.lock:
            self.should_stop = True

# 测试时可以尝试不同的设备节点
a = VideoThread(device="/dev/video0")  # 先尝试video0
a.start()
time.sleep(300)
a.stop()
a.join()

